LEÇON 7

Programmation Fonctionnelle en Python

Fonctions lambda, map, filter, reduce, et listes en compréhension

Français - Programmation Fonctionnelle

Qu'est-ce que la programmation fonctionnelle ? C'est un paradigme qui traite le calcul comme l'évaluation de fonctions mathématiques, sans état mutable ni effets de bord. Python supporte plusieurs concepts fonctionnels.

1. Fonctions Lambda (Fonctions Anonymes)

Les fonctions lambda sont des fonctions sans nom, idéales pour des opérations simples et courtes.

# Syntaxe: lambda paramètres: expression

# Fonction classique
def carre_classique(x):
    return x ** 2

# Lambda équivalente
carre_lambda = lambda x: x ** 2
print(carre_lambda(5)) # 25

# Lambda avec plusieurs paramètres
somme = lambda a, b: a + b
print(somme(10, 3)) # 13

# Utilisation immédiate d'une lambda
resultat = (lambda x, y: x * y)(4, 7)
print(resultat) # 28

2. La fonction map()

map() applique une fonction à chaque élément d'un itérable et retourne un itérateur.

# Appliquer une fonction à chaque élément d'une liste
nombres = [1, 2, 3, 4, 5]

# Avec une fonction classique
def double(x):
    return x * 2
doubles = list(map(double, nombres))
print(doubles) # [2, 4, 6, 8, 10]

# Avec une lambda (plus concis)
triples = list(map(lambda x: x * 3, nombres))
print(triples) # [3, 6, 9, 12, 15]

# map() avec plusieurs listes
a = [1, 2, 3]
b = [10, 20, 30]
somme_listes = list(map(lambda x, y: x + y, a, b))
print(somme_listes) # [11, 22, 33]

3. La fonction filter()

filter() filtre les éléments d'un itérable selon une fonction de prédicat (qui retourne True ou False).

# Filtrer les nombres pairs
nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

pairs = list(filter(lambda x: x % 2 == 0, nombres))
print("Nombres pairs:", pairs) # [2, 4, 6, 8, 10]

# Filtrer les chaînes plus longues que 3 caractères
mots = ["chat", "python", "le", "programmation", "est"]
mots_long = list(filter(lambda mot: len(mot) > 3, mots))
print("Mots > 3 caractères:", mots_long)

# Filtrer les None, False, 0, etc. (valeurs falsy)
valeurs = [0, 1, False, "hello", None, "", 42]
valides = list(filter(None, valeurs)) # None comme filtre enlève les falsy
print("Valeurs truthy:", valides) # [1, "hello", 42]

4. La fonction reduce()

reduce() applique une fonction cumulativement aux éléments d'un itérable pour le réduire à une seule valeur. (Module functools)

from functools import reduce

# Calculer le produit de tous les nombres
nombres = [1, 2, 3, 4, 5]
produit = reduce(lambda x, y: x * y, nombres)
print("Produit:", produit) # 120 (1*2*3*4*5)

# Trouver le maximum
maximum = reduce(lambda x, y: x if x > y else y, nombres)
print("Maximum:", maximum) # 5

# Concaténer des chaînes
mots = ["Python", "est", "puissant"]
phrase = reduce(lambda a, b: a + " " + b, mots)
print("Phrase:", phrase) # "Python est puissant"

# reduce() avec valeur initiale
somme = reduce(lambda x, y: x + y, nombres, 100)
print("Somme + 100:", somme) # 115

5. Listes en Compréhension (List Comprehensions)

Les listes en compréhension sont une façon élégante et pythonique de créer des listes.

# Syntaxe: [expression for élément in itérable if condition]

# Carrés des nombres de 1 à 10
carres = [x**2 for x in range(1, 11)]
print("Carrés:", carres)

# Avec condition : nombres pairs seulement
pairs = [x for x in range(20) if x % 2 == 0]
print("Pairs:", pairs)

# Transformer des données
temperatures_c = [0, 20, 30, 100]
temperatures_f = [(c * 9/5) + 32 for c in temperatures_c]
print("°F:", temperatures_f)

# Boucles imbriquées
coordonnees = [(x, y) for x in range(3) for y in range(3)]
print("Coordonnées:", coordonnees)
Comparaison : map vs compréhension
map(lambda x: x*2, liste)[x*2 for x in liste]
Les compréhensions sont souvent plus lisibles et plus "pythoniques".

6. Autres compréhensions (Dictionnaires, Ensembles)

# Dictionnaire en compréhension
carres_dict = {x: x**2 for x in range(1, 6)}
print("Dict carrés:", carres_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Inverser clé/valeur
original = {"a": 1, "b": 2, "c": 3}
inverse = {v: k for k, v in original.items()}
print("Inverse:", inverse) # {1: 'a', 2: 'b', 3: 'c'}

# Ensemble en compréhension
nombres = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = {x for x in nombres}
print("Valeurs uniques:", unique) # {1, 2, 3, 4}

# Ensemble des lettres d'un mot
lettres = {c for c in "programmation"}
print("Lettres uniques:", lettres)

7. Fonctions map, filter et compréhensions comparées

# Exemple : prendre les carrés des nombres pairs
nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Avec map et filter combinés
resultat1 = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, nombres)))
print("Avec map+filter:", resultat1)

# Avec compréhension (plus lisible)
resultat2 = [x**2 for x in nombres if x % 2 == 0]
print("Avec compréhension:", resultat2)
Bonnes pratiques :
  • Préférez les compréhensions pour des transformations simples
  • Utilisez map() et filter() avec des fonctions déjà définies
  • Évitez les lambdas trop complexes (préférez une fonction nommée)
  • reduce() est moins courant - parfois une boucle est plus claire

English - Functional Programming

What is functional programming? It's a paradigm that treats computation as the evaluation of mathematical functions, without mutable state or side effects. Python supports several functional concepts.

1. Lambda Functions (Anonymous Functions)

Lambda functions are nameless functions, ideal for simple and short operations.

# Syntax: lambda parameters: expression

# Classic function
def square_classic(x):
    return x ** 2

# Equivalent lambda
square_lambda = lambda x: x ** 2
print(square_lambda(5)) # 25

# Lambda with multiple parameters
add = lambda a, b: a + b
print(add(10, 3)) # 13

# Immediate lambda usage
result = (lambda x, y: x * y)(4, 7)
print(result) # 28

2. The map() Function

map() applies a function to every element of an iterable and returns an iterator.

# Apply a function to each element of a list
numbers = [1, 2, 3, 4, 5]

# With a classic function
def double(x):
    return x * 2
doubles = list(map(double, numbers))
print(doubles) # [2, 4, 6, 8, 10]

# With a lambda (more concise)
triples = list(map(lambda x: x * 3, numbers))
print(triples) # [3, 6, 9, 12, 15]

# map() with multiple lists
a = [1, 2, 3]
b = [10, 20, 30]
sum_lists = list(map(lambda x, y: x + y, a, b))
print(sum_lists) # [11, 22, 33]

3. The filter() Function

filter() filters elements of an iterable according to a predicate function (returns True or False).

# Filter even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

evens = list(filter(lambda x: x % 2 == 0, numbers))
print("Even numbers:", evens) # [2, 4, 6, 8, 10]

# Filter strings longer than 3 characters
words = ["cat", "python", "the", "programming", "is"]
long_words = list(filter(lambda w: len(w) > 3, words))
print("Words > 3 chars:", long_words)

# Filter out None, False, 0, etc. (falsy values)
values = [0, 1, False, "hello", None, "", 42]
valid = list(filter(None, values)) # None as filter removes falsy
print("Truthy values:", valid) # [1, "hello", 42]

4. The reduce() Function

reduce() applies a function cumulatively to the elements of an iterable to reduce it to a single value. (Module functools)

from functools import reduce

# Calculate product of all numbers
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print("Product:", product) # 120 (1*2*3*4*5)

# Find maximum
maximum = reduce(lambda x, y: x if x > y else y, numbers)
print("Maximum:", maximum) # 5

# Concatenate strings
words = ["Python", "is", "powerful"]
sentence = reduce(lambda a, b: a + " " + b, words)
print("Sentence:", sentence) # "Python is powerful"

# reduce() with initial value
total = reduce(lambda x, y: x + y, numbers, 100)
print("Sum + 100:", total) # 115

5. List Comprehensions

List comprehensions are an elegant and Pythonic way to create lists.

# Syntax: [expression for element in iterable if condition]

# Squares of numbers 1 to 10
squares = [x**2 for x in range(1, 11)]
print("Squares:", squares)

# With condition: even numbers only
evens = [x for x in range(20) if x % 2 == 0]
print("Evens:", evens)

# Transform data
celsius = [0, 20, 30, 100]
fahrenheit = [(c * 9/5) + 32 for c in celsius]
print("°F:", fahrenheit)

# Nested loops
coordinates = [(x, y) for x in range(3) for y in range(3)]
print("Coordinates:", coordinates)
Comparison: map vs comprehension
map(lambda x: x*2, list)[x*2 for x in list]
Comprehensions are often more readable and more "Pythonic".

6. Other Comprehensions (Dict, Set)

# Dictionary comprehension
squares_dict = {x: x**2 for x in range(1, 6)}
print("Dict squares:", squares_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Invert key/value
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print("Inverted:", inverted) # {1: 'a', 2: 'b', 3: 'c'}

# Set comprehension
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = {x for x in numbers}
print("Unique values:", unique) # {1, 2, 3, 4}

# Unique letters of a word
letters = {c for c in "programming"}
print("Unique letters:", letters)

7. Comparing map, filter and comprehensions

# Example: square of even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# With map and filter combined
result1 = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers)))
print("With map+filter:", result1)

# With comprehension (more readable)
result2 = [x**2 for x in numbers if x % 2 == 0]
print("With comprehension:", result2)
Best practices:
  • Prefer comprehensions for simple transformations
  • Use map() and filter() with pre-defined functions
  • Avoid overly complex lambdas (prefer a named function)
  • reduce() is less common - sometimes a loop is clearer